/*
 * Piece.java
 *
 * This work is free software; you can redistribute it and/or
 * modify it under the terms of the Apache License as published 
 * by the Apache Software Foundation.
 *
 * This work is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * Apache License for more details.
 *
 * Copyright (c) 2011 Tran Hoang Anh (tranhoanganh89@gmail.com). 
 * All rights reserved.
 */
package net.hoanganh.jbraintetris;

import java.awt.Color;
import java.awt.Point;

/**
 * A piece is formed by connected squares. Each type of piece have specific
 * color and can rotate 0, 90, 180 or 270 counter clockwise.
 */
public class Piece {

	/**
	 * Color for piece.
	 */
	private Color color;

	/**
	 * Origin position for squares of piece.
	 */
	private Point[] originPositions;

	/**
	 * The integer that indicate rotated degree in order 0, 90, 180, 270. It
	 * have value between 0 and 3.
	 */
	private int orientation;

	/**
	 * The maximum orientation and also bigger than orientation. This value is
	 * used to limit rotation transform because some piece such as square only
	 * have one appearance even in any rotation transform.
	 */
	private int maxOrientation;

	/**
	 * Initialize new piece.
	 * 
	 * @param originPositions
	 *            origin position for squares of piece
	 * 
	 * @param maxOrientation
	 *            the maximum orientation 
	 * 
	 * @param color
	 * 		      color for piece
	 */
	public Piece(Point[] originPositions, int maxOrientation, Color color) {
		if (originPositions == null || originPositions.length == 0) {
			throw new IllegalArgumentException("originPositions is not valid.");
		}		
		if (maxOrientation <= 0) {
			throw new IllegalArgumentException("maxOrientation is not negative.");
		}
		if (color == null) {
			throw new IllegalArgumentException("color is not null.");
		}
		
		this.originPositions = originPositions;
		this.maxOrientation = maxOrientation;
		this.color = color;
		
		reset();
	}
	
	/**
	 * Get piece color.
	 * 
	 * @return the color
	 */
	public Color getColor() {
		return color;
	}

	/**
	 * Get origin positions.
	 * 
	 * @return the originPositions
	 */
	public Point[] getOriginPositions() {
		return originPositions;
	}

	/**
	 * Get orientation.
	 * 
	 * @return the orientation
	 */
	public int getOrientation() {
		return orientation;
	}
	
	/**
	 * Set orientation.
	 */
	public void setOrientation(int orientation) {
		if (orientation < 0 || orientation >= maxOrientation) {
			throw new IllegalArgumentException("orientation is not valid.");
		}
		this.orientation = orientation;
	}

	/**
	 * Get max orientation.
	 * 
	 * @return the maxOrientation
	 */
	public int getMaxOrientation() {
		return maxOrientation;
	}

	/**
	 * Rotate counter clockwise.
	 */
	public void rotate() {
		orientation = (orientation == 0)? maxOrientation - 1 : orientation - 1;
	}
	
	/**
	 * Reset to initialized state.
	 */
	public void reset() {
		this.orientation = 0;
	}
	
	/**
	 * Get current position.
	 * 
	 * @return array of point representing current position.
	 */
	public Point[] getPositions() {
		Point[] result = new Point[originPositions.length];
		for (int i = 0; i<result.length; i++) {
			result[i] = new Point();
			result[i].x = originPositions[i].x;
			result[i].y = originPositions[i].y;
		}
		
		for (Point p : result) {
			transform(p);
		}
		return result;		
	}

	/**
	 * Transform origin position to current position using rotation matrix.
	 * 
	 * @param p
	 * 			origin point which need to transform
	 */
	private void transform(Point p) {
		int x = p.x;
		int y = p.y;
		
		switch (orientation) {
		case 0: // 0
			p.x = x;
			p.y = y;
			break;
		case 1: // 90
			p.x = -y;
			p.y = x;
			break;
		case 2: // 180
			p.x = -x;
			p.y = -y;
			break;
		case 3: // 270
			p.x = y;
			p.y = -x;
			break;
		default:
			break;
		}
	}
}
